// DrawPolygon
/*
绘制面
 */
class DrawPolygon {
    constructor(arg) {
        this.Cesium = arg.Cesium;
        this.callback = arg.callback;
        this._polygon = null; //活动面
        this._polygonLast = null; //最后一个面
        this._positions = []; //活动点
        this._entities_point = []; //脏数据
        this._entities_polygon = []; //脏数据
        this._polygonData = null; //用户构造面
        this._entities_labels = []; //用于显示面积结果
        this.currentHeight = 0.0;
        this.maxValue = 0.0;
    }

    setViewer(earth) {
        this.viewer = earth.czm.viewer;
    }

    setThisWidget() {
        let self = this;
        this.thisWidget = {
            entity: null,
            drawOk: function (e) {
                this.entity = e;
                var t = this.computePolygonHeightRange(
                    e.polygon.hierarchy.getValue().positions
                );
                (this.currentHeight = t.minHeight), (this.maxValue = t.maxHeight);
            },
            computePolygonHeightRange: function (e) {
                let viewer = self.viewer;
                var t = [];
                for (var i = 0; i < e.length; i++) t.push(e[i].clone());
                var a,
                    n,
                    r,
                    o,
                    s,
                    u,
                    l,
                    h = 0,
                    g = 9999,
                    c = Math.PI / Math.pow(2, 11) / 64,
                    m = new Cesium.PolygonGeometry.fromPositions({
                        positions: t,
                        vertexFormat: Cesium.PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
                        granularity: c,
                    }),
                    d = new Cesium.PolygonGeometry.createGeometry(m);
                for (i = 0; i < d.indices.length; i += 3)
                    (a = d.indices[i]),
                        (n = d.indices[i + 1]),
                        (r = d.indices[i + 2]),
                        (l = new Cesium.Cartesian3(
                            d.attributes.position.values[3 * a],
                            d.attributes.position.values[3 * a + 1],
                            d.attributes.position.values[3 * a + 2]
                        )),
                        (o = viewer.scene.globe.getHeight(
                            Cesium.Cartographic.fromCartesian(l)
                        )) < g && (g = o),
                        h < o && (h = o),
                        (l = new Cesium.Cartesian3(
                            d.attributes.position.values[3 * n],
                            d.attributes.position.values[3 * n + 1],
                            d.attributes.position.values[3 * n + 2]
                        )),
                        (s = viewer.scene.globe.getHeight(
                            Cesium.Cartographic.fromCartesian(l)
                        )) < g && (g = s),
                        h < s && (h = s),
                        (l = new Cesium.Cartesian3(
                            d.attributes.position.values[3 * r],
                            d.attributes.position.values[3 * r + 1],
                            d.attributes.position.values[3 * r + 2]
                        )),
                        (u = viewer.scene.globe.getHeight(
                            Cesium.Cartographic.fromCartesian(l)
                        )) < g && (g = u),
                        h < u && (h = u);
                return {
                    maxHeight: h,
                    minHeight: g,
                };
            },
            startFx: function (e) {
                self.viewer.scene.globe.depthTestAgainstTerrain = !0;
                var t = self;
                (this.extrudedHeight = e),
                    (this.entity.polygon.extrudedHeight = new Cesium.CallbackProperty(
                        function (e) {
                            return t.extrudedHeight;
                        },
                        false
                    ));

                for (
                    var i = this.entity.polygon.hierarchy.getValue().positions, a = [], n = 0;
                    n < i.length;
                    n++
                ) {
                    var r = Cesium.Ellipsoid.WGS84.cartesianToCartographic(i[n]),
                        o = {
                            lon: Cesium.Math.toDegrees(r.longitude),
                            lat: Cesium.Math.toDegrees(r.latitude),
                            hgt: e,
                        },
                        s = [o.lon, o.lat, o.hgt];
                    a = a.concat(s);
                }
                return (
                    (i = Cesium.Cartesian3.fromDegreesArrayHeights(a)),
                    (this.entity.polygon.hierarchy = new Cesium.CallbackProperty(function (
                        e
                    ) {
                        return i;
                    },
                        false)),
                    !0
                );
            },
            clear: function () {
                (this.viewer.scene.globe.depthTestAgainstTerrain = !1),
                    (this.entity = null);
            },
            updateHeight: function (e) {
                this.entity.polygon.extrudedHeight = e;
            },
        };
    }

    //返回最后活动面
    get polygon() {
        return this._polygonLast;
    }

    //返回面数据用于加载面
    getData() {
        return this._polygonData;
    }

    //加载面
    loadPolygon(data) {
        var $this = this;
        let uid = $this.guid();
        this.viewer.entities.add({
            id: uid,
            polygon: {
                hierarchy: new $this.Cesium.PolygonHierarchy(data),
                // perPositionHeight: true,
                show: true,
                fill: true,
                material: new Cesium.ColorMaterialProperty(Cesium.Color.LIGHTSKYBLUE.withAlpha(0.7)),
                // width: 3,
                // outlineColor: $this.Cesium.Color.BLACK,
                // outlineWidth: 1,
                // outline: true,
                clampToGround: true,
            },
        });
        return uid;
    }

    //开始绘制
    startCreate() {
        var $this = this;
        $this.clear();

        //#region  添加一个cylinder，不然水面有闪烁情况
        this.viewer.entities.add({
            name: 'Green cylinder with black outline',
            position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 200000.0),
            cylinder: {
                length: 400000.0,
                topRadius: 200000.0,
                bottomRadius: 200000.0,
                material: Cesium.Color.GREEN.withAlpha(0.5),
                outline: true,
                outlineColor: Cesium.Color.DARK_GREEN
            },
            show: false
        });
        //#endregion

        this.handler = new this.Cesium.ScreenSpaceEventHandler(
            this.viewer.scene.canvas
        );
        this.handler.setInputAction(function (evt) {
            const pick = $this.viewer.scene.pick(evt.position);
            if (pick && pick.id) {
                if (pick.id.label && pick.id.label.text._value === "结束画面") {
                    // if (!$this._polygon) return;
                    // $this._positions.pop()
                    $this._polygonData = $this._positions.concat();
                    $this.viewer.entities.remove($this._positions); //移除
                    var polygon_id = $this.loadPolygon($this._polygonData);
                    $this._entities_polygon.push(polygon_id);
                    $this._polygonLast = polygon_id;
                    $this.viewer.entities.getById(
                        $this._entities_point[$this._entities_point.length - 1]
                    ).label = null; //去除结束画面标签

                    let param = [];
                    var ellipsoid = $this.viewer.scene.globe.ellipsoid;
                    for (var i = 0; i < $this._positions.length; i++) {
                        var cartographic = ellipsoid.cartesianToCartographic(
                            $this._positions[i]
                        );
                        var lat = $this.Cesium.Math.toDegrees(cartographic.latitude);
                        var lng = $this.Cesium.Math.toDegrees(cartographic.longitude);
                        var height = cartographic.height;
                        param.push(lng);
                        param.push(lat);
                        param.push(height);
                    }
                    $this.destroy();
                    $this.thisWidget.drawOk($this.viewer.entities.getById(polygon_id));
                    $this.int = self.setInterval(() => {
                        $this.thisWidget.currentHeight > $this.thisWidget.maxValue
                            ? (clearInterval($this.int))
                            : ($this.thisWidget.updateHeight($this.thisWidget.currentHeight),
                                ($this.thisWidget.currentHeight += 1));
                    }, 100);
                    return;
                }
            }
            //单击开始绘制
            var cartesian = $this.getCatesian3FromPX(evt.position);
            let uid = $this.guid();
            $this.createPoint(cartesian, uid);
            $this._positions.push(cartesian);
        }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }

    //创建面
    createPolygon(uid) {
        var $this = this;
        this.viewer.entities.add({
            id: uid,
            polygon: {
                hierarchy: new $this.Cesium.CallbackProperty(function () {
                    return new $this.Cesium.PolygonHierarchy($this._positions);
                }, false),
                // perPositionHeight: true,
                show: true,
                fill: true,
                material: $this.Cesium.Color.WHITE.withAlpha(0.1),
                width: 5,
                outlineColor: $this.Cesium.Color.BLACK,
                outlineWidth: 1,
                outline: true,
                clampToGround: true,
            },
        });
        $this._entities_polygon.push(uid);
        return uid;
    }

    //创建点
    createPoint(cartesian, uid) {
        if (this._entities_point.length > 1 && this._positions.length > 1) {
            var last_point = this.viewer.entities.getById(
                this._entities_point[this._entities_point.length - 1]
            );
            last_point.label = null;
            last_point.billboard = null;
        }

        var $this = this;
        var point;
        if (this._positions.length >= 2) {
            point = this.viewer.entities.add({
                id: uid,
                position: cartesian,
                point: {
                    pixelSize: 10,
                    color: $this.Cesium.Color.YELLOW,
                },
                label: {
                    //文字标签
                    text: "结束画面",
                    font: "500 15px Helvetica", // 15pt monospace
                    scale: 1.0,
                    style: Cesium.LabelStyle.FILL,
                    fillColor: Cesium.Color.WHITE,
                    pixelOffset: new Cesium.Cartesian2(0, -70), //偏移量
                    showBackground: true,
                    backgroundColor: new Cesium.Color(
                        26 / 255,
                        196 / 255,
                        228 / 255,
                        1.0
                    ),
                },
            });
        } else {
            point = this.viewer.entities.add({
                id: uid,
                position: cartesian,
                point: {
                    pixelSize: 10,
                    color: $this.Cesium.Color.YELLOW,
                },
            });
        }
        $this._entities_point.push(uid);
        return point;
    }

    //销毁事件
    destroy() {
        if (this.handler) {
            this.handler.destroy();
            this.handler = null;
        }
    }

    //清空实体对象
    clear() {
        for (var i = 0; i < this._entities_point.length; i++) {
            this.viewer.entities.removeById(this._entities_point[i]);
        }
        for (var j = 0; j < this._entities_polygon.length; j++) {
            this.viewer.entities.removeById(this._entities_polygon[j]);
        }

        for (var m = 0; m < this._entities_polygon.length; m++) {
            this.viewer.entities.removeById(this._entities_labels[m]);
        }

        this._polygon = null; //活动面
        this._polygonLast = null; //最后一个面
        this._positions = []; //活动点
        this._entities_point = []; //脏数据
        this._entities_polygon = []; //脏数据
        this._polygonData = null; //用户构造面
    }

    getCatesian3FromPX(px) {
        // 两个pick联合使用，可以解决pickPosition不稳定的问题和global.pick不能找模型高度的问题
        var cartesian1;
        var cartesian2;
        var ray = this.viewer.camera.getPickRay(px);
        if (!ray) return null;
        cartesian1 = this.viewer.scene.globe.pick(ray, this.viewer.scene);

        if (this.viewer.scene.pickPositionSupported) {
            if (this.viewer.scene.mode !== Cesium.SceneMode.MORPHING) {
                if (!this.viewer.scene.globe.depthTestAgainstTerrain) {
                    this.viewer.scene.globe.depthTestAgainstTerrain = true
                }
                cartesian2 = this.viewer.scene.pickPosition(px);
            }
        } else {
            //如果不支持pickPosition,则返回undefined
            console.log("This browser does not support pickPosition.");
            cartesian2 = undefined;
        }

        let real_cartesian = undefined;
        if (typeof cartesian2 == "undefined") {
            real_cartesian = cartesian1;
        } else {
            real_cartesian = cartesian2;
        }
        return real_cartesian;
        // return cartesian1
    }

    //用海伦公式获取传入坐标的构成的多边形的面积。
    getSurfaceArea(positions) {
        if (positions.length < 3) {
            return 0;
        }
        const {
            Cartesian3,
            EllipsoidTangentPlane,
            Ellipsoid,
            Math: CesiumMath,
            PolygonGeometryLibrary,
            PolygonHierarchy,
            VertexFormat,
        } = Cesium;
        const perPositionHeight = true;
        // 获取组成多边形的三角形。
        const tangentPlane = EllipsoidTangentPlane.fromPoints(
            positions,
            Ellipsoid.WGS84
        );
        const polygons = PolygonGeometryLibrary.polygonsFromHierarchy(
            new PolygonHierarchy(positions),
            tangentPlane.projectPointsOntoPlane.bind(tangentPlane),
            !perPositionHeight,
            Ellipsoid.WGS84
        );

        const geom = PolygonGeometryLibrary.createGeometryFromPositions(
            Ellipsoid.WGS84,
            polygons.polygons[0],
            CesiumMath.RADIANS_PER_DEGREE,
            perPositionHeight,
            VertexFormat.POSITION_ONLY
        );

        if (
            geom.indices.length % 3 !== 0 ||
            geom.attributes.position.values.length % 3 !== 0
        ) {
            // 不是三角形，无法计算。
            return 0;
        }
        const coords = [];
        for (let i = 0; i < geom.attributes.position.values.length; i += 3) {
            coords.push(
                new Cartesian3(
                    geom.attributes.position.values[i],
                    geom.attributes.position.values[i + 1],
                    geom.attributes.position.values[i + 2]
                )
            );
        }
        let area = 0;
        for (let i = 0; i < geom.indices.length; i += 3) {
            const ind1 = geom.indices[i];
            const ind2 = geom.indices[i + 1];
            const ind3 = geom.indices[i + 2];

            const a = Cartesian3.distance(coords[ind1], coords[ind2]);
            const b = Cartesian3.distance(coords[ind2], coords[ind3]);
            const c = Cartesian3.distance(coords[ind3], coords[ind1]);

            // 海伦公式
            const s = (a + b + c) / 2.0;
            area += Math.sqrt(s * (s - a) * (s - b) * (s - c));
        }
        return area;
    }

    /**
     * generateUUID 生成UUID
     * @returns {string} 返回字符串
     */
    generateUUID() {
        var d = new Date().getTime();
        var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (
            c
        ) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == "x" ? r : (r & 0x7) | 0x8).toString(16);
        });
        return uuid;
    }

    // 获取多边形的质心
    getCentroid(pgon) {
        var value = [];
        var center = [];
        var a = 0;
        var b = 0;
        for (var j = 0; j <= pgon._hierarchy._value.positions.length - 1; j++) {
            value[j] = [
                pgon._hierarchy._value.positions[j].x,
                pgon._hierarchy._value.positions[j].y,
            ];
            a = pgon._hierarchy._value.positions[j].z;
            b = b + a;
        }

        // 让最后一个点与第一个点相同才能让turf组成多边形
        value[pgon._hierarchy._value.positions.length] = [
            pgon._hierarchy._value.positions[0].x,
            pgon._hierarchy._value.positions[0].y,
        ];

        // eslint-disable-next-line no-undef
        var polygon = turf.polygon([value]);
        // eslint-disable-next-line no-undef
        var centroid = turf.centroid(polygon);
        center = [
            centroid.geometry.coordinates[0],
            centroid.geometry.coordinates[1],
            b / pgon._hierarchy._value.positions.length,
        ];
        return Cesium.Cartesian3.fromArray(center);
    }

    guid() {
        return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
            var r = (Math.random() * 16) | 0,
                v = c == "x" ? r : (r & 0x3) | 0x8;
            return v.toString(16);
        });
    }
}

export default DrawPolygon;
